/*
 * Licensed under Beer is great.
 * If You want to use this buy me a beer (Svijany 11 will be enough)
 */

package dtd.to.xml;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Class which parses DTD file and stores information 
 * into ArrayLists (one for Element , Attribute and Entity)
 * 
 * @author martin
 */
public class DTDParser {
    private final String path;
    private List<DTDElement> DTDElements;
    private List<DTDAttribute> DTDAttributes;
    private List<DTDEntity> DTDEntities;    
    
    /**
     * Constructor for class DTD_parser
     * @param givenPath path to the DTD
     */
    public DTDParser(String givenPath){
        DTDAttributes = new ArrayList<>();
        DTDElements = new ArrayList<>();
        DTDEntities = new ArrayList<>();
        path = givenPath;        
    }
    
    /**
     * method which parse DTD file
     * @throws IOException 
     */
    public void parseDTD() throws IOException{
        BufferedReader br = null;
        try {
             br = new BufferedReader(new FileReader(path));
        } catch (FileNotFoundException ex) {
            Logger.getLogger(DTDParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        String line = null;
        String buffer = "";
        while ((line = br.readLine()) != null){            
            if(line.contains("<!ELEMENT")){
                if(line.contains(">")){            
                    DTDElements.add(createElement(line));                    
                }
                else{
                    line = readOneDTDLine(br,line);           
                    DTDElements.add(createElement(line));                    
                }
                    
            }
            else if (line.contains("<!ATTLIST")){
                if(line.contains(">")){
                    line = line.replaceAll("\\s+", " ");        
                    DTDAttributes.addAll(createAttribute(line));
                }
                else{
                    line = readOneDTDLine(br,line);
                    line = line.replaceAll("\\s+", " ");
                    DTDAttributes.addAll(createAttribute(line));
                }
            }
            else if (line.contains("<!ENTITY")){
                if(line.contains(">")){
                    line = line.replaceAll("\\s+", " ");
                    DTDEntities.add(createEntity(line));
                }
                else{
                    line = readOneDTDLine(br,line);
                    line = line.replaceAll("\\s+", " ");
                    DTDEntities.add(createEntity(line));
                }
            }
                
        }                
    }
    
    private String readOneDTDLine(BufferedReader br , String line) throws IOException{
        String buffer = line;
        while (!buffer.contains(">")){
                        line = br.readLine();                        
                        buffer += line;                        
                    }
        return buffer;
    }
    
    public DTDElement createElement(String info){              
        String[] split = split(info , false);                            
        DTDElement returned = new DTDElement(split[1] , split[2]);        
        return returned;
    }
    
    public List<DTDAttribute> createAttribute(String info){        
        String[] split = split(info.trim(), true);        
        List<DTDAttribute> returned = new ArrayList<>();
                
        for(int i = 2; i < split.length - 2; i++){
            String otherInfo = split[i+1] +" " + split[i+2];
            if(split[i+2].equals("#FIXED")){
                otherInfo += " " + split[i+3];
                i = i+3;
            }
            returned.add(new DTDAttribute(split[1],split[i],otherInfo));
            i = i+2;
        }        
        return Collections.unmodifiableList(returned);
    }
    
    public DTDEntity createEntity(String info){
        String[] split = split(info,false);
        DTDEntity returned = new DTDEntity(split[1],split[2]);
        return returned;
    }
    
    private String[] split(String info, boolean att){
        info = info.replaceAll("\\s+", " ");
        info = info.replaceAll(">", " >");
        info = info.replaceAll(",", ", ");
        info = info.replaceAll("\\( ", "\\(");
        info = info.replaceAll(", ", ",");
        info = info.replaceAll(" ,", ",");
        info = info.replaceAll("\\| ", "\\|");
        info = info.replaceAll(" \\|", "\\|");
        String[] split = null;
        if(!att){
            split = info.split(" ", 3);
            split[2] = split[2].replaceAll("\\s+", "");
            split[2] = split[2].substring(0, split[2].length() - 1);
        }
        else{            
            split = info.split(" ");
            split[split.length - 1] = split[split.length - 1].substring(0, split[split.length - 1].length() - 1);
        }
        return split;
    }
    
    /**
     * Getter for Elements
     * @return List of Elements
     */
    public List<DTDElement> getElements(){
        return Collections.unmodifiableList(DTDElements);
    }
    
    /**
     * Getter for Entities
     * @return List of Entities
     */
    public List<DTDEntity> getEntities(){
        return Collections.unmodifiableList(DTDEntities);
    }
    
    /**
     * Getter for Attributes
     * @return List of Attributes
     */
    public List<DTDAttribute> getAttributes(){
        return Collections.unmodifiableList(DTDAttributes);
    }
}
